﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using WPFServices.Model;
using Wpf2.ViewModels;
using Wpf2.Models;
using WPFServices;



namespace Wpf2.Views
{
    /// <summary>
    /// Interaction logic for OutInventory.xaml
    /// can kiem tra lai buoc xac minh Customer: nhập trùng tên => MessageBox => No => xoa du liệu ???? đúng ko? hay là giữ nguyên rồi lúc sau nào đó lại kiểm tra
    /// </summary>
    public partial class OutInventory
    {
        readonly USER _user = new USER();
        readonly Customer _newCustomer = new Customer { IsHaveToCheck = true};
        bool _canExcuteTextChangedEvent = true;
        public ICommand SaveOrder { get; set; }
        public ICommand PrintOrder { get; set; }
        NotifiableCollection<Catalogs> _catalogs;
        readonly PaymentInfomation _paymentInfo = new PaymentInfomation();
        readonly InventoryViewModel _outInventoryVm = new InventoryViewModel();
        public ObservableCollection<Products> ObsProducts = new ObservableCollection<Products>();

       
        

        public OutInventory()
        {
            try
            {
                InitializeComponent();
                txtUserID.DataContext = _user;
                panelOfCustomer.DataContext = _newCustomer;
                LoadListCatalogIntoListView();
                InitializeDataGridForProducts();
                panelOfPaymentInfomation.DataContext = _paymentInfo;
                ObsProducts = _outInventoryVm.obsProducts;
                InitializeSaveOrderCommand();
                chkDahoacuong.DataContext = _outInventoryVm;
                
                
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        

    #region -- define ICommand: SaveOrder ---

        private void InitializeSaveOrderCommand()
        {
            try
            {
                SaveOrder = new RelayCommand<object>
            (
                CanExcutedSaveOrderCommand,
                SaveOrderToDataBase
            );

                PrintOrder = new RelayCommand<object>
                    (
                        CanExcutedPrintCommand,
                        PrintOrderFunc
                    );
                btnPrint.Command = PrintOrder;
                btnSaveOrder.Command = SaveOrder;
                btnSaveOrder.CommandParameter = dtgInventory.ItemsSource;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

       private void PrintOrderFunc(object obj)
        {
            try
            {
                var fEditBeforePrint = new FormEditBeforePrintOutInventory(_outInventoryVm.removeAllNullProduct(), _user, _newCustomer, _paymentInfo, _outInventoryVm.IsMarble);
                fEditBeforePrint.ShowDialog();
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message);
            }
        }

        private bool CanExcutedPrintCommand(object obj)
        {
            // neu da duoc lưu => đã thỏa các điều kiện
            return _outInventoryVm.IsSaved;
        }

        private bool CanExcutedSaveOrderCommand(object obj)
        {
            return !string.IsNullOrEmpty(txtUserID.Text) && WPFServices.Services.UserService.GetUser(_user.ID_USER??0) != null && IsExistProduct() && !_outInventoryVm.IsSaved;
        }

        public bool IsExistProduct()
        {
            return _outInventoryVm.ListProductsForAddInvetory.Any(pro => pro.ProductIdAuto > 0 && pro.InventoryCount > 0);
        }

        public void SaveOrderToDataBase(object o)
        {
            try
            {
                if (_outInventoryVm.NumberrOfSaved > 0)
                    if (MessageBox.Show("Hóa đơn sẽ được tạo mới. Bạn có muốn tiếp tục lưu hóa đơn?", "Xác Nhận!", MessageBoxButton.YesNo) == MessageBoxResult.No)
                        return;
                CheckOrCreateCustomer();
                var idOrder = CreateNewOrder();
                CreateListOfOrderDetails(idOrder);
                _outInventoryVm.isSaved();
                MessageBox.Show("Lưu thành công");
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message);
            }
        }
        /// <summary>
        /// Thêm vào csdl thông tin danh sách sản phẩm xuất và trừ đi số lượng || dài, rông, m2
        /// </summary>
        /// <param name="idOrder">Mã Order</param>
        private void CreateListOfOrderDetails(int idOrder)
        {
            try
            {
                // thêm vào pro.TotalOutPayment > 0 để xác định M2 có > 0 hay k? (trường hợp dài rộng)
                foreach (var pro in _outInventoryVm.ListProductsForAddInvetory.Where(pro => !string.IsNullOrEmpty(pro.ProductId) && pro.InventoryCount >0 && pro.TotalOutPayment > 0))
                {
                    if (_outInventoryVm.IsMarble)
                        WPFServices.Services.Products.UpdateInvetoryCountByProductID(pro.ProductId, -pro.InventoryCount, -pro.ProductWidth, -pro.ProductHeight);
                    else
                        WPFServices.Services.Products.UpdateInvetoryCountByProductID(pro.ProductId, -pro.InventoryCount);
                    CreateNewOrderDetail(idOrder, pro.ProductIdAuto, pro.InventoryCount, pro.IsCostPrice, pro.ProductHeight, pro.ProductWidth, pro.ProductM2);
                }
            }
            catch (Exception)
            {
                throw new Exception("Lỗi khi tạo OrderDetails");
            }
        }

        private void CheckOrCreateCustomer()
        {
            try
            {
                if (_newCustomer.IdCus != 0) return;
                _newCustomer.IdCus = string.IsNullOrEmpty(_newCustomer.CusName) ? WPFServices.Services.CustomersService.GetOrGreateDefaultCustomer() : WPFServices.Services.CustomersService.InsertCustomer(new ModelCustomers { NameCus = _newCustomer.CusName, ADDRESS = _newCustomer.Address, PHONE = _newCustomer.Phone });
            }
            catch (Exception)
            {
                throw new Exception("Lỗi khi kiểm tra và thêm khách hàng");
            }
        }

        /// <summary>
        /// Tạo mới trong CSDL ORDER mới
        /// </summary>
        /// <returns>Order ID : Mã hóa đơn</returns>
        private int CreateNewOrder()
        {
            try
            {
                var catalogs = lvCatalog.SelectedItem as Catalogs;
                if (catalogs == null)
                {
                    return 0;
                }
                var newOrder = new ORDER
                                   {
                                       ID_CUS = _newCustomer.IdCus,
                                       // mặc định để xác định là trường hợp nhập kho, cần thêm chức năng kiểm tra => tạo nếu không có
                                       ID_USER = _user.ID_USER??0, // phai lay user hien tai
                                       ID_CATALOG = catalogs.IDCatalog, //khong biet lay cai nao??
                                       ORDER_TYPE = 1, //Xác định loại hóa đơn 1: xuất || 0: nhập
                                       DATE_ORD = DateTime.Now,
                                       OLD_DEBTS = _paymentInfo.OldDebts,
                                       PRE_PAID = _paymentInfo.PrePaid,
                                       TOTAL = _paymentInfo.TotalPayment,
                                       STATUS_ORD = _paymentInfo.Remain == 0 ? "0" : "1",
                                       ORDER_TYPES = _outInventoryVm.IsMarble ? 1 : 0 // xác định loại hóa đơn Đá Hoa Cương: 1 => Đá Hoa Cương || 0 => Loại thường
                                   };
                return WPFServices.Services.Orders.CreateOrder(newOrder);
            }
            catch (Exception e)
            {
                throw new Exception("Lỗi khi tạo Order mới"+e.Message);
            }
        }

        /// <summary>
        /// Tạo mới trong csdl OrderDetail
        /// </summary>
        /// <param name="iOrderID">Mã Hóa đơn</param>
        /// <param name="iProductIdAuto">Mã sản phẩm</param>
        /// <param name="iInventoryCount">Số lượng</param>
        /// <param name="isCostPrice">trong cơ sở dữ liệu là biến bit: 0 là giá lẽ, 1 là giá sỉ</param>
        private static void CreateNewOrderDetail(int iOrderID, int iProductIdAuto, int iInventoryCount, bool isCostPrice, double dHeight, double dWidth, double dM2)
        {
            try
            {
                var newOrderDetail = new ORDER_DETAILS
                {
                    ID_ORD = iOrderID,
                    ID_PRO_AUTO = iProductIdAuto,
                    QUANTITY = iInventoryCount,
                    HEIGHT = dHeight,
                    WIDTH = dWidth,
                    M2 = dM2,
                    ACTIVEPRICE = isCostPrice
                };
                WPFServices.Services.OrderDetails.CreateOrderDetail(newOrderDetail);
            }
            catch (Exception)
            {
                throw new Exception("Lỗi khi tạo OrderDetail mới");
            }
        }

    #endregion

        /// <summary>
        /// Load danh sách Catalog
        /// </summary>
        private void LoadListCatalogIntoListView()
        {
            try
            {
                var listCa = WPFServices.Services.Catalogs.GetListCatalogs().Select(x => new Catalogs
                {
                IDCatalog = x.ID_CATALOG,
                CatalogName = x.NAME_CATALOG,
                CatalogNotes = x.NOTES_CATALOG
                });
                _catalogs = new NotifiableCollection<Catalogs>();
                foreach (Catalogs c in listCa)
                {
                    _catalogs.Add(c);
                }
                lvCatalog.DataContext = _catalogs;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

    #region --- DataGrid For Inventory:Product
        /// <summary>
        /// Chỉ định ItemsSource
        /// Xử lý xự kiện thêm 1 dòng (thêm 1 Product)
        /// Xử lý đánh số thứ tự
        /// </summary>
        private void InitializeDataGridForProducts()
        {
            try
            {
                dtgInventory.ItemsSource = _outInventoryVm.ListProductsForAddInvetory;
                dtgInventory.RowEditEnding += DtgInventoryRowEditEnding;
                dtgInventory.LoadingRow += DtgInventoryLoadingRow;
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message);
            }
        }

        private static void DtgInventoryLoadingRow(object sender, DataGridRowEventArgs e)
        {
            try
            {
                e.Row.Header = e.Row.GetIndex() + 1;
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message);
            }
        }

        private void DtgInventoryRowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
        {
            try
            {
                //xử lý nếu ở dòng cuối mà đã có sản phẩm rổng thì k thêm dòng mới
                if (!_outInventoryVm.lastProductIsNull())
                {
                    _outInventoryVm.addProduct(new Products());
                }
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message);
            }
        }
    #endregion


    #region --- AutoComplete txtProductName use Combobox ---
        private void ComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            try
            {
                _canExcuteTextChangedEvent = false; // when get content's Commbobox to set text's textbox => TextChanged will be excuted => stop event
                var cmbListToChoose = sender as ComboBox;
                if (cmbListToChoose != null)
                {
                    var stp = cmbListToChoose.Parent as Grid;
                    if (stp != null)
                    {
                        var txtProductName = stp.Children[0] as TextBox;
                        var cbItem = (ComboBoxItem)cmbListToChoose.SelectedItem;
                        if (txtProductName != null)
                        {
                            var p = txtProductName.DataContext as Products;

                            var np = WPFServices.Services.Products.GetProduct(int.Parse(cbItem.Tag.ToString()));

                            if (null != cmbListToChoose.SelectedItem)
                            {
                                if (p != null)
                                {
                                    p.ProductIdAuto = np.ID_PRO_AUTO;
                                    p.ProductName = np.NAME_PRO;
                                    p.ProductId = np.ID_PRO;
                                    p.ProductDescription = np.DESCRIPTIONS;
                                    if (np.DETAILS_PRODUCTS.COST_PRICES != null)
                                        p.CostPrice = (decimal)np.DETAILS_PRODUCTS.COST_PRICES;
                                    if (np.DETAILS_PRODUCTS.SELL_PRICE != null)
                                        p.SellPrice = (decimal)np.DETAILS_PRODUCTS.SELL_PRICE;
                                    p.Unit = new Unit { UnitID = np.DETAILS_PRODUCTS.UNIT.ID_UNIT, UnitName = np.DETAILS_PRODUCTS.UNIT.NAME_UNIT, UnitNote = np.DETAILS_PRODUCTS.UNIT.NOTES_UNIT };
                                    p.catalog = new Catalogs { CatalogName = np.CATALOG.NAME_CATALOG, CatalogNotes = np.CATALOG.NOTES_CATALOG, IDCatalog = np.CATALOG.ID_CATALOG };
                                }
                            }
                        }
                    }
                }
                _canExcuteTextChangedEvent = true;
                if (!_outInventoryVm.lastProductIsNull())
                    _outInventoryVm.addProduct(new Products());
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message);
            }
        }

        private void TxtProductNameTextChanged(object sender, TextChangedEventArgs e)
        {
            try
            {
                if (!_canExcuteTextChangedEvent) // specify is event can run or not
                    return;
                var txtProductName = sender as TextBox;
                if (txtProductName != null)
                {
                    var p = txtProductName.DataContext as Products;
                    if (p != null && !string.IsNullOrEmpty(p.ProductName)) // if text's textbox change when exist Product was binded => delete Product and create new Product to find
                    {
                        var index = _outInventoryVm.ListProductsForAddInvetory.IndexOf(p);
                        _outInventoryVm.ListProductsForAddInvetory.RemoveAt(index);
                        _outInventoryVm.ListProductsForAddInvetory.Insert(index, new Products());
                        return;
                    }
                }
                Grid stp = null;
                if (txtProductName != null) stp = txtProductName.Parent as Grid;
                if (stp == null) return;
                var cmbListToChoose = stp.Children[1] as ComboBox;
                if (cmbListToChoose == null) return;
                cmbListToChoose.Items.Clear();
                LoadComboboxItem(txtProductName.Text, cmbListToChoose);
                cmbListToChoose.IsDropDownOpen = cmbListToChoose.HasItems;
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message);
            }
        }

        private void TxtProductNameLostFocus(object sender, RoutedEventArgs e)
        {
            try
            {
                var txtProductName = sender as TextBox;
                if (txtProductName == null) return;
                var stp = txtProductName.Parent as Grid;
                if (stp == null) return;
                var cmbListToChoose = stp.Children[1] as ComboBox;
                if (cmbListToChoose != null) cmbListToChoose.IsDropDownOpen = false;
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message);
            }
        }

        private void LoadComboboxItem(string searchString, ItemsControl comboboxResult)
        {
            try
            {
                foreach (var cbItem in from item in ObsProducts where !string.IsNullOrEmpty(searchString) where !IsExistInProductList(_outInventoryVm.ListProductsForAddInvetory, item) where item.ProductId.StartsWith(searchString, StringComparison.CurrentCultureIgnoreCase) select new ComboBoxItem {Content = item.ProductId, Tag = item.ProductIdAuto})
                    comboboxResult.Items.Add(cbItem);
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message);
            }
        }

        private static bool IsExistInProductList(IEnumerable<Products> productList, Products product)
        {
            return productList.Any(item => item.ProductId == product.ProductId);
        }

        // just accept numberic is input into textbox
    /*    private void TxtInventoryCountPreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            if (!char.IsDigit(e.Text, e.Text.Length - 1))
            {
                e.Handled = true;
            }
        }*/
    #endregion


        private void TxtAcceptNumbericPreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            if(!char.IsDigit(e.Text, e.Text.Length-1))
                e.Handled = true;
        }

        private void TxtInvetoryCountTextChanged(object sender, TextChangedEventArgs e)
        {

            try
            {
                var textBox = sender as TextBox;
                if (textBox != null)
                {
                    var pro = textBox.DataContext as Products;

                    if (pro != null && (!string.IsNullOrEmpty(pro.ProductName) && pro.InventoryCount > WPFServices.Services.Products.GetProduct(pro.ProductIdAuto).DETAILS_PRODUCTS.INVENTORY_COUNT))

                        if (MessageBox.Show("Số lượng vược quá trong kho! Bạn có muốn lưu hay không?", "Thống báo", MessageBoxButton.YesNo) == MessageBoxResult.No)
                        {
                            pro.InventoryCount = 0;
                            return;
                        }
                }
                // đã chuyển qua xử lý trong set{};
                //pro.totalPayment = pro.InventoryCount * pro.SellPrice;
                CaculationPaymentForAllProduct();
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message);
            }
        }

        private void CaculationPaymentForAllProduct()
        {
            try
            {
                _paymentInfo.SumOut = 0;
                foreach (var pro in _outInventoryVm.ListProductsForAddInvetory.Where(pro => !string.IsNullOrEmpty(pro.ProductId)))
                    _paymentInfo.SumOut += pro.TotalOutPayment;
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message);
            }
        }

    
        private void TxtProductNameKeydown(object sender, KeyEventArgs e)
        {
            try
            {
                var txt = sender as TextBox;
                if (txt == null) return;
                var p = txt.DataContext as Products;
                if (e.Key != Key.Enter) return;
                var np = WPFServices.Services.Products.GetProductByID(txt.Text);
                if (np == null) return;
                if (p != null)
                {
                    p.ProductIdAuto = np.ID_PRO_AUTO;
                    p.ProductName = np.NAME_PRO;
                    p.ProductId = np.ID_PRO;
                    p.ProductDescription = np.DESCRIPTIONS;
                    if (np.DETAILS_PRODUCTS.COST_PRICES != null) p.CostPrice = (decimal)np.DETAILS_PRODUCTS.COST_PRICES;
                    p.Unit = new Unit { UnitID = np.DETAILS_PRODUCTS.UNIT.ID_UNIT, UnitName = np.DETAILS_PRODUCTS.UNIT.NAME_UNIT, UnitNote = np.DETAILS_PRODUCTS.UNIT.NOTES_UNIT };
                    p.catalog = new Catalogs { CatalogName = np.CATALOG.NAME_CATALOG, CatalogNotes = np.CATALOG.NOTES_CATALOG, IDCatalog = np.CATALOG.ID_CATALOG };
                }
                if (!_outInventoryVm.lastProductIsNull())
                    _outInventoryVm.ListProductsForAddInvetory.Add(new Products());
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message);
            }

        }
        /// <summary>
        /// thêm mới để bắt sự kiện khi người dùng thay đổi loại giá của hóa đơn xuất
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void chboxIsCostPrice_checked(object sender, RoutedEventArgs e)
        {
            CaculationPaymentForAllProduct();
        }

        /// <summary>
        /// Hàm sử dụng khi có thay đổi về dài rộng. Mục đích tính toán payment
        ///  ::: sự kiện này sai vì thuộc tính của dài rộng là update = LostFocus nên hàm này sẽ thực thi truoc khi dài rộng được cập nhật => tính toán chậm 1 nhịp
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CaculationPayment(object sender, TextChangedEventArgs e)
        {
            CaculationPaymentForAllProduct();
        }
        /// <summary>
        /// Hàm sử dụng khi có thay đổi về dài rộng. Mục đích tính toán payment
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CaculationPayment(object sender, RoutedEventArgs e)
        {
            CaculationPaymentForAllProduct();
        }

    }
}



    public class PaymentInfomation : PropertyChangedBase
    {
        decimal _oldDebts;
        private decimal _sumOut;
        private decimal _remain;
        private decimal _prePaid;
        private decimal _totalPayment;


        public decimal OldDebts
        {
            get { return _oldDebts; }
            set { _oldDebts = value; TotalPayment = value + SumOut; OnPropertyChanged("OldDebts"); }
        }
        

        public decimal PrePaid
        {
            get { return _prePaid; }
            set { _prePaid = value; Remain = TotalPayment - value; OnPropertyChanged("PrePaid"); }
        }
        

        public decimal SumOut
        {
            get { return _sumOut; }
            set { _sumOut = value; TotalPayment = value + OldDebts; OnPropertyChanged("SumOut"); }
        }
        
        // = tong toa + no cu
        public decimal TotalPayment
        {
            get { return _totalPayment; }
            set { _totalPayment = value; Remain = value - PrePaid; OnPropertyChanged("TotalPayment"); }
        }
        
        // = tong cong - gui trc
        public decimal Remain
        {
            get { return _remain; }
            set { _remain = value; OnPropertyChanged("Remain"); }
        }
    }
